﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using DatabaseCore;
using DatabaseCore.Dto;
using System.Data.SqlClient;
using System.Data;
using SystemCore.Helper;
using Export.SAP.Service;
using OGA.NPI.ICSH.ServiceBase.Entities;
using System.Data.Entity.Core.Objects;

namespace Export.Transfer.Service
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                Console.WriteLine("Start at " + DateTime.Now.ToString());
                ExceptionHelper.LogAppError("Start at " + DateTime.Now.ToString());
                List<ProductMovementTemp> prodMove = getProductMovement();

                Console.WriteLine(string.Format("Get product move  {0} record(s)", prodMove.Count));
                ExceptionHelper.LogAppError(string.Format("Get product move  {0} record(s)", prodMove.Count));

                List<ProdQueue> q = getQueue();
                List<ProdQueue> qCompleted;
                List<tbl_Transaction> tCompleted;
                Console.WriteLine(string.Format("Get q  {0} record(s)", q.Count));
                ExceptionHelper.LogAppError(string.Format("Get q  {0} record(s)", q.Count));

                Console.WriteLine("Start process queue " + DateTime.Now.ToString());
                ExceptionHelper.LogAppError("Start process queue " + DateTime.Now.ToString());

                processQueue(q, prodMove, out qCompleted, out tCompleted);
                Console.WriteLine("Done process queue " + DateTime.Now.ToString());
                ExceptionHelper.LogAppError("Done process queue " + DateTime.Now.ToString());

                bool isSapMoveSuccess = true;
                updateSAP(tCompleted, out tCompleted, out isSapMoveSuccess);
                if (!isSapMoveSuccess)
                {
                    updateTransactionFailed(tCompleted);
                    Console.WriteLine("Done! do not need to continues " + DateTime.Now.ToString());
                }
                else
                {

                    Console.WriteLine("Done call sap " + DateTime.Now.ToString());
                    ExceptionHelper.LogAppError("Done call sap " + DateTime.Now.ToString());

                    updateQueue(q, tCompleted);
                    Console.WriteLine("Done update queue back" + DateTime.Now.ToString());
                    ExceptionHelper.LogAppError("Done update queue back" + DateTime.Now.ToString());
                }
            }
            catch (Exception ex)
            {

                ExceptionHelper.LogAppError(ex.Message );
                ExceptionHelper.LogAppError(ex.StackTrace );
                ExceptionHelper.LogAppError(ex.Source);
            }
            
            ExceptionHelper.LogAppError("##########################################################################################");
        }


        private static List<ProductMovementTemp> getProductMovement()
        {
            using (var ctx = new ExportDBEntities())
            {
                var pm = (from productMove in ctx.ProductMovementTemp
                          orderby productMove.UpdateDatetime descending
                          where productMove.IsUsed != true &&productMove.UpdateDatetime != null & productMove.UpdateDatetime > EntityFunctions.AddMinutes(DateTime.Now, -5)
                         select  productMove).Take(1000);
                return pm.ToList();
            }
        }

        private static List<ProdQueue> getQueue()
        {
            using (var ctx = new ExportDBEntities())
            {
                var q = (from prodQueue in ctx.ProdQueue
                        where prodQueue.IsActive == true
                        select prodQueue).ToList();

                var sp = (from specialPercent in ctx.ProductSpecialPercent
                          where specialPercent.IsActive == true && DateTime.Today >= specialPercent.StartDate && DateTime.Today <= specialPercent.EndDate
                         select specialPercent).ToList();

                foreach (var s in sp)
                {
                    foreach (var queue in q)
                    {
                        if (queue.ProductCode == s.ProductCode)
                        {
                            queue.RateProcess = s.PercentSpecial;
                        }
                    }
                }

                foreach (var qProcess in q)
                {
                    qProcess.IsProcessing = true;
                }

                //ctx.SaveChanges();
                return q;
            }
        }

        private static void processQueue(List<ProdQueue> qs, List<ProductMovementTemp> pMove, out List<ProdQueue> qCompleted,
            out List<tbl_Transaction> tCompleted)
        {
            List<tbl_Transaction> ts = new List<tbl_Transaction>();
            foreach (var p in pMove)
            {
                var plant = p.PlantDestination ?? p.PlantCode;
                int qty = -1;
                foreach (var q in qs)
                {
                    if (q.ProductCode == p.ProductCode && q.PlantCode == plant && q.IsMoveBySAP != true)
                    {
                        if (qty != -1)
                        {
                            qty = Convert.ToInt32((qty * (q.RateProcess == 0 ? 20 : q.RateProcess)) / 100);
                        }
                        else
                        {
                            qty = Convert.ToInt32((p.BaseUnitQty * (q.RateProcess == 0 ? 20 : q.RateProcess)) / 100);
                        }

                        var productMap = new tbl_Transaction();
                        productMap.MaterialNo = q.ProductCode;
                        productMap.OrderNo = q.OrderNo;
                        productMap.PalletDetailId = p.PalletDetailID;
                        productMap.Plant = string.IsNullOrEmpty(p.PlantDestination) ? p.PlantCode : p.PlantDestination;
                        productMap.UpdateBy = "Queue Mapped";
                        productMap.UpdateDate = DateTime.Now;
                        if (q.Qty > qty)
                        {
                            productMap.Qty = qty;
                            q.Qty = q.Qty - qty;
                            productMap.Qty = qty;
                            ts.Add(productMap);
                            break;
                        }
                        else
                        {
                            qty = qty - (int)q.Qty;
                            q.IsMoveBySAP = true;
                            productMap.Qty = Convert.ToInt32(q.Qty);
                            ts.Add(productMap);
                        }

                    }
                }
            }
            qCompleted = qs;
            tCompleted = ts;
        }

        private static void updateSAP(List<tbl_Transaction> ts, out List<tbl_Transaction> tsAfterSap, out bool ismoveSuccess)
        {
            tsAfterSap = ts;
            var sap = new ProductMovement();
            int processId = -1;
            ismoveSuccess = true;
            ResponseGoodsMovementEntity result = sap.productMove(ts, out processId);
            if (result.Result)
            {
                tsAfterSap.ForEach(t => t.Result = result.MaterialDocumentNo);
                tsAfterSap.ForEach(t => t.StockNo = processId.ToString());
            }
            else
            {
                ismoveSuccess = false;
                tsAfterSap.ForEach(t=>t.Result = result.MessageDescription + " doc year =" + result.DocumentYear);
            }
        }

        private static void updateQueue(List<ProdQueue> qs,List<tbl_Transaction> ts)
        {
            ProdQueueDao qProvider = new ProdQueueDao();
            TransactionDao tProvider = new TransactionDao();
            OrderDetailDao ddProvider = new OrderDetailDao();
            OrderDao dProvider = new OrderDao();
            qProvider.ClearData();
            qs.ForEach(q => q.IsProcessing = false);
            qs.ForEach(q => q.Rate = 20);
            qProvider.InsertCollection(qs.Where(q=>q.IsMoveBySAP != true).ToList());
            ts.ForEach(t => t.Qty = t.Qty * -1);
            tProvider.InsertCollection(ts);
            updateProductTemp(ts);
            ddProvider.UpdateQueueMapQty(ts);
            dProvider.UpdateToCloseJob(checkIsCloseDoc(qs));
        }

        private static void updateTransactionFailed(List<tbl_Transaction> ts)
        {
            TransactionDao tProvider = new TransactionDao();
            ts.ForEach(t => t.Qty = 0);
            ts.ForEach(t => t.IsMoveCompleted = false);
            tProvider.InsertCollection(ts);
        }

        private static void updateProductTemp(List<tbl_Transaction> ts)
        {
            using (var ctx = new ExportDBEntities())
            {
                foreach (var t in ts)
                {
                    ProductMovementTemp pm = (from p in ctx.ProductMovementTemp
                                       where p.PalletDetailID == t.PalletDetailId
                                       select p).FirstOrDefault();

                    if (pm != null)
                    {
                        pm.IsUsed = true;
                    }
                }

                ctx.SaveChanges();
            }
        }

        private static List<string> checkIsCloseDoc(List<ProdQueue> q)
        {
            OrderDao dProvider = new OrderDao();
            List<string> docs = new List<string>();
            var qGroup = q.GroupBy(d => d.OrderNo);
            foreach (var t in qGroup)
            {
                var count = t.Count(c => c.IsMoveBySAP != true);

                var getAllQTy = dProvider.CheckOrderIsClose(t.Key);
                if (count == 0 && getAllQTy){
                    docs.Add(t.FirstOrDefault().OrderNo);
                }
            }
            return docs;
        }

    }
}
